import cv2;
import numpy as np;

def darkchannel(im, sz):
    # 将图像拆分成三个通道
    b, g, r = cv2.split(im)
    # 计算出每个像素的三个通道中的最小值，即暗通道
    dc = cv2.min(cv2.min(r, g), b);
    # 使用腐蚀操作对暗通道进行处理
    dark = cv2.erode(dc, cv2.getStructuringElement(cv2.MORPH_RECT, (sz, sz)))
    # 返回腐蚀后的暗通道图像
    return dark

def estimate_atmosphericlight(im, dark, percent=0.001):
    # 计算了用于估计大气光的总像素数
    total_pixels = int(im.shape[0] * im.shape[1] * percent)
    # 将dark图像数组展平并进行升序排序,使用负索引选择最亮像素的索引
    brightest_indices = np.argsort(dark.flatten())[-total_pixels:]
    # 对展平后的im图像数组进行索引，以获取最亮的像素
    brightest_pixels = im.reshape(-1, 3)[brightest_indices]
    # 计算brightest_pixels数组沿着第一个轴的均值,计算选定的最亮像素的RGB值的平均值
    A = np.mean(brightest_pixels, axis=0)
    # 将A转换为一维数组
    A = np.expand_dims(A, axis=0)
    return A

def estimate_t_prob(im, A, sz):
    # 控制透射率的估计过程中的权重
    omega = 0.95;
    # 将用于存储归一化后的图像
    im3 = np.empty(im.shape, im.dtype);
    for ind in range(0, 3):
        # 原始图像的每个通道上的像素值除以大气光的对应通道的值
        im3[:, :, ind] = im[:, :, ind] / A[0, ind]
    # 将omega乘以暗通道图像，并将结果从1中减去，得到最终的透射率
    transmission = 1 - omega * darkchannel(im3, sz);
    # 返回估计的透射率图像
    return transmission

def estimate_t_acc(im, et):
    # 将输入的彩色图像im转换为灰度图像
    gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY);
    # 将灰度图像的像素值从整数范围（0-255）转换为浮点数范围（0-1）
    gray = np.float64(gray) / 255;
    # 定义滤波器的半径r,参数eps
    r = 60;
    eps = 0.0001;
    # 高斯滤波
    # 确保滤波器的半径 r 是一个正奇数
    r = r if r % 2 == 1 else r + 1
    # 对灰度图像进行高斯滤波，得到滤波后的图像 mean_I
    mean_I = cv2.GaussianBlur(gray, (r, r), 0);
    # 对输入的透射率图像 et 进行高斯滤波，得到滤波后的图像 mean_p
    mean_p = cv2.GaussianBlur(et, (r, r), 0);
    # 对灰度图像和透射率图像的乘积进行高斯滤波，得到滤波后的图像 mean_Ip
    mean_Ip = cv2.GaussianBlur(gray * et, (r, r), 0);
    # 计算协方差矩阵
    cov_Ip = mean_Ip - mean_I * mean_p;
    # 对灰度图像的平方进行盒滤波，得到滤波后的图像mean_II
    mean_II = cv2.boxFilter(gray * gray, cv2.CV_64F, (r, r));
    # 计算方差矩阵
    var_I = mean_II - mean_I * mean_I;
    # 计算引导滤波器的系数 a，用于调整透射率图像
    a = cov_Ip / (var_I + eps);
    # 计算引导滤波器的偏置项 b，用于调整透射率图像
    b = mean_p - a * mean_I;
    # 对系数图像 a 进行高斯滤波，得到滤波后的图像 mean_a
    mean_a = cv2.GaussianBlur(a, (r, r), 0)
    # 对偏置图像 b 进行高斯滤波，得到滤波后的图像 mean_b
    mean_b = cv2.GaussianBlur(b, (r, r), 0)
    # 使用滤波后的系数图像 mean_a 和偏置图像 mean_b 对灰度图像 gray 进行线性组合，得到细化后的透射率图像 q
    q = mean_a * gray + mean_b;
    # 返回经过细化处理后的透射率图像q
    return q;

def defog(im, t, A, tx=0.1):
    # 用于存储恢复后的图像结果
    res = np.empty(im.shape, im.dtype);
    # 将透射率图像 t 中的每个像素值与阈值 tx 进行比较，并选择较大的值作为新的透射率
    t = cv2.max(t, tx);
    for ind in range(0, 3):
        # 将输入图像 im 的每个通道上的像素值减去对应的光照值
        channel = im[:, :, ind]
        channel_minus_A = channel - A[0, ind]
        # 将结果除以透射率 t，并加上光照值
        channel_res = channel_minus_A / t + A[0, ind]
        # 将恢复后的通道结果赋值给结果图像的对应通道
        res[:, :, ind] = channel_res
    # 返回恢复后的图像结果
    return res

fn = ('./image/5.png')
pg = cv2.imread(fn)
# 将图像数据类型转换为float64，并将像素值归一化到[0,1]的范围。将处理后的图像赋值给变量I
I = pg.astype('float64')/255
# 计算暗通道图像
dark = darkchannel(I, 15)
# 计算大气光值
A = estimate_atmosphericlight(I, dark)
# 计算透射率图像
t_prob = estimate_t_prob(I, A, 15)
# 获得细化后的透射率图像
t = estimate_t_acc(pg, t_prob)
# 获得去雾后的图像
J = defog(I, t, A, 0.1)
cv2.imshow("darkchannel", dark)
cv2.imshow("get_t", t)
cv2.imshow('I', pg)
cv2.imshow('J', J)
cv2.imwrite("./image/J.png", J*255)
cv2.waitKey()


